package com.aplink.generic.xmlparser;

import java.io.IOException;
import java.util.Iterator;

import javax.xml.parsers.ParserConfigurationException;

import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import android.content.Context;
import android.content.res.Resources;
import android.text.TextUtils;

import com.aplink.generic.constant.ObjProConstant;
import com.aplink.generic.constant.WebServiceContant;
import com.aplink.generic.dictionary.GenericDictionary;
import com.aplink.generic.pojo.ContentData;
import com.aplink.generic.pojo.ObjPropInfo;
import com.aplink.generic.pojo.TableRelationship;

public class ContentDataParser {

    private static ContentDataParser sInstance = null;

    public static ContentDataParser getInstance() {
        synchronized (ContentDataParser.class) {
            if (ContentDataParser.sInstance == null) {
                ContentDataParser.sInstance = new ContentDataParser();
            }
        }
        return ContentDataParser.sInstance;
    }

    private static String getTextNodeValue(final Node node) {
        Node child;
        if (node != null) {
            if (node.hasChildNodes()) {
                child = node.getFirstChild();
                while (child != null) {
                    if (child.getNodeType() == Node.TEXT_NODE) {
                        return child.getNodeValue();
                    }
                    child = child.getNextSibling();
                }
            }
        }
        return "";
    }

    @SuppressWarnings("unchecked")
    private static ContentData parse(final Document doc, final String tagname) {
        final ContentData objPropCol = new ContentData();
        if (doc == null) {
            return objPropCol;
        }
        final Element propElement = doc.getDocumentElement();
        final String webserviceFunction = propElement
                .getAttribute(WebServiceContant.XmlTagName.WEBSERVICE_FUNCTION);
        if (webserviceFunction != null) {
            objPropCol.setWebserviceFunction(webserviceFunction);
        }
        final NodeList propNodeList = doc
                .getElementsByTagName(ObjProConstant.OBJ_PROP);
        for (int i = 0; i < propNodeList.getLength(); i++) {
            Node node = propNodeList.item(i);
            String p_om_id = null;

            String webserviceParameter = null;
            if (node.hasAttributes()) {
                webserviceParameter = XMLPaserUtil.getAttrValue(node,
                        WebServiceContant.XmlTagName.WEBSERVICE_PARAMETER);
                p_om_id = XMLPaserUtil.getAttrValue(node,
                        ObjProConstant.OBJ_PROP_P_OM_ID);

            }
            Element element = (Element) node;
            final NodeList nList = element
                    .getElementsByTagName(ObjProConstant.OBJ_PROP_TAGNAME);
            final JSONObject jsonObject = new JSONObject();
            for (int temp = 0; temp < nList.getLength(); temp++) {
                String joinType = null;
                String webserviceVariable = null;
                Node nNode = nList.item(temp);
                if (nNode.hasAttributes()) {
                    webserviceVariable = XMLPaserUtil.getAttrValue(nNode,
                            WebServiceContant.XmlTagName.WEBSERVICE_VARIABLE);
                }
                final ObjPropInfo objPropInfo = new ObjPropInfo();
                boolean isSortedAsc = false;
                boolean isSortedDesc = false;
                objPropInfo.setTableRoot(p_om_id);
                if (nNode.getNodeType() == Node.ELEMENT_NODE) {
                    String content = "";
                    element = (Element) nNode;
                    // get ID of this property
                    NodeList nodes = element
                            .getElementsByTagName(ObjProConstant.OBJ_CLASS_ID);
                    if (nodes.getLength() != 0) {
                        content = ContentDataParser.getTextNodeValue(nodes
                                .item(0));
                        objPropInfo.setTableName(content); // done
                    }

                    // get ID of this property
                    nodes = element
                            .getElementsByTagName(ObjProConstant.OBJ_PROP_ID);
                    if (nodes.getLength() != 0) {
                        content = ContentDataParser.getTextNodeValue(nodes
                                .item(0));
                        objPropInfo.setColumnName(content);

                        // check isKey,
                        nNode = nodes.item(0);
                        final Element elementchild = (Element) nNode;
                        String value = XMLPaserUtil.getAttrValue(nNode,
                                ObjProConstant.IS_LATTITUDE);
                        if (!TextUtils.isEmpty(value)) {
                            if (value.equalsIgnoreCase("Y")) {
                                objPropInfo.setLatitude(true);
                            }
                        }

                        value = XMLPaserUtil.getAttrValue(nNode,
                                ObjProConstant.IS_LONGITUDE);
                        if (!TextUtils.isEmpty(value)) {
                            if (value.equalsIgnoreCase("Y")) {
                                objPropInfo.setLongitude(true);
                            }
                        }

                        final String sortASC = XMLPaserUtil.getAttrValue(nNode,
                                ObjProConstant.OBJ_PROP_IS_SORTED_ASC);

                        final String sortDESC = XMLPaserUtil.getAttrValue(
                                nNode, ObjProConstant.OBJ_PROP_IS_SORTED_DESC);
                        final String groupBy = XMLPaserUtil.getAttrValue(nNode,
                                ObjProConstant.OBJ_PROP_IS_GROUP_BY);
                        final String isCreatedTime = XMLPaserUtil.getAttrValue(
                                nNode, ObjProConstant.OBJ_PROP_IS_CREATED_TIME);
                        final String isSyncStatus = XMLPaserUtil.getAttrValue(
                                nNode, ObjProConstant.OBJ_PROP_IS_SYNC_STATUS);
                        final String isImageServerPath = XMLPaserUtil
                                .getAttrValue(
                                        nNode,
                                        ObjProConstant.OBJ_PROP_IS_IMAGE_SERVER_PATH);
                        final String isImageLocalPath = XMLPaserUtil
                                .getAttrValue(nNode,
                                        ObjProConstant.IS_IMAGE_LOCAL_PATH);

                        final String isToken = XMLPaserUtil.getAttrValue(nNode,
                                ObjProConstant.IS_TOKEN);

                        final String isUsername = XMLPaserUtil.getAttrValue(
                                nNode, ObjProConstant.IS_USERNAME);
                        final String isDeviceID = XMLPaserUtil.getAttrValue(
                                nNode, ObjProConstant.IS_DEVICE_ID);
                        if (!TextUtils.isEmpty(isDeviceID)
                                && isDeviceID.equalsIgnoreCase("Y")) {
                            objPropInfo.setDeviceID(true);
                        }
                        final String isPassword = XMLPaserUtil.getAttrValue(
                                nNode, ObjProConstant.IS_PASSWORD);
                        if ((groupBy != null) && groupBy.equalsIgnoreCase("Y")) {
                            objPropInfo.setGroupBy(true);
                        }

                        if ((sortASC != null) && sortASC.equalsIgnoreCase("Y")) {
                            isSortedAsc = true;
                        } else if ((sortDESC != null)
                                && sortDESC.equalsIgnoreCase("Y")) {
                            isSortedDesc = true;
                        }

                        if (isSortedAsc) {
                            objPropCol.addASCColumn(objPropInfo
                                    .getFullColumnName());
                        } else if (isSortedDesc) {
                            objPropCol.addDESCColumn(objPropInfo
                                    .getFullColumnName());
                        }
                        if (objPropInfo.isGroupBy()) {
                            objPropCol.addGroupBy(objPropInfo
                                    .getFullColumnName());
                        }
                        if ((isToken != null) && isToken.equalsIgnoreCase("Y")) {
                            objPropInfo.setToken(true);
                        }
                        if ((isUsername != null)
                                && isUsername.equalsIgnoreCase("Y")) {
                            objPropInfo.setUsername(true);
                        }
                        if ((isPassword != null)
                                && isPassword.equalsIgnoreCase("Y")) {
                            objPropInfo.setPassword(true);
                        }
                        if ((isSyncStatus != null)
                                && isSyncStatus.equalsIgnoreCase("Y")) {
                            objPropInfo.setSyncStatus(true);
                            objPropCol.addSyncStatus(objPropInfo);
                        }
                        if ((isCreatedTime != null)
                                && isCreatedTime.equalsIgnoreCase("Y")) {
                            objPropInfo.setCreatedTime(true);
                            objPropCol.addCreatedTimeObject(objPropInfo);
                        }
                        if ((isImageLocalPath != null)
                                && isImageLocalPath.equalsIgnoreCase("Y")) {
                            objPropInfo.setImageLocalPath(true);
                            objPropCol.setImageLocalPath(objPropInfo);
                        }
                        if ((isImageServerPath != null)
                                && isImageServerPath.equalsIgnoreCase("Y")) {
                            objPropInfo.setImageServerPath(true);
                            objPropCol.setImageServerPath(objPropInfo);
                        }

                        if (webserviceVariable != null) {
                            objPropInfo
                                    .setWebserviceVariable(webserviceVariable);
                        }

                        final String ignore = XMLPaserUtil.getAttrValue(nNode,
                                ObjProConstant.SAVE);
                        if ((ignore != null) && ignore.equalsIgnoreCase("N")) {
                            objPropInfo.setSave(false);
                        }

                        joinType = XMLPaserUtil.getAttrValue(nNode, "join");

                        final String iskey = elementchild
                                .getAttribute(ObjProConstant.OBJ_PROP_ISKEY);
                        if (iskey.equalsIgnoreCase("Y")) {
                            objPropInfo.setKey(true); // done
                            objPropCol.addPrimaryKeys(objPropInfo);
                            if (objPropCol.getMainTable() == null) {
                                objPropCol.setMainTable(objPropInfo.getTable());
                            }
                        }
                        final String isAuto = elementchild
                                .getAttribute(ObjProConstant.OBJ_PROP_ISAUTO);
                        if (isAuto.equalsIgnoreCase("Y")) {
                            objPropInfo.setIsAuto(true);
                        }
                        // or (isFKey, fkeyID)
                        final String isfkey = elementchild
                                .getAttribute(ObjProConstant.OBJ_PROP_ISFKEY);
                        if (isfkey.equalsIgnoreCase("Y")) {
                            objPropInfo.setFKey(true); // done
                            if (joinType == null) {
                                joinType = "INNER JOIN";
                            }
                        }

                        final String f_table_id = elementchild
                                .getAttribute(ObjProConstant.OBJ_PROP_F_OM_ID);
                        if (!TextUtils.isEmpty(f_table_id)) {
                            objPropInfo.setForeignObjectMapping(f_table_id); // done

                            final String tableRelationShip = elementchild
                                    .getAttribute(ObjProConstant.RELATIONSHIP);
                            if ((tableRelationShip != null)
                                    && !tableRelationShip.isEmpty()) {
                                objPropInfo.setRelationship(TableRelationship
                                        .get(tableRelationShip));
                                objPropCol.addForiegnKeys(objPropInfo);
                            }
                        }
                        final String foriegnKeyId = elementchild
                                .getAttribute(ObjProConstant.OBJ_PROP_FKEYID);
                        if (!foriegnKeyId.isEmpty()) {
                            objPropInfo.setForiegnKey(foriegnKeyId);
                        }

                        // get datatype of this property
                        nodes = element
                                .getElementsByTagName(ObjProConstant.OBJ_PROP_DATATYPE);
                        if (nodes.getLength() != 0) {
                            content = ContentDataParser.getTextNodeValue(nodes
                                    .item(0));
                            objPropInfo.setDataType(content); // done
                        }

                        if (objPropInfo.isFKey()) {
                            String primaryTable = null;
                            String foriegnTable = null;
                            String leftCondition = null;
                            String rightCondition = null;

                            if (p_om_id == null) {
                                primaryTable = objPropInfo.getTable();
                                foriegnTable = objPropInfo.getForeignTable();

                                if (objPropCol.isContainTable(foriegnTable)) {
                                    primaryTable = null;
                                }
                                leftCondition = objPropInfo.getFullColumnName();
                                rightCondition = objPropInfo
                                        .getForeignFullColumnName();
                            } else if (p_om_id != null) {
                                primaryTable = null;
                                foriegnTable = objPropInfo.getForeignTable();
                                leftCondition = objPropInfo.getFullColumnName();
                                rightCondition = objPropInfo
                                        .getForeignFullColumnName();
                            }
                            objPropCol
                                    .addJoin(primaryTable, joinType,
                                            foriegnTable, leftCondition,
                                            rightCondition);
                        }
                    }

                    nodes = element
                            .getElementsByTagName(ObjProConstant.OBJ_PROP_EXPRESS);
                    if (nodes.getLength() == 1) {
                        content = ContentDataParser.getTextNodeValue(nodes
                                .item(0));
                        if (!TextUtils.isEmpty(content)) {
                            objPropInfo.setExpress(content);
                        }
                    }

                    nodes = element
                            .getElementsByTagName(ObjProConstant.DATA_RULES);
                    if (nodes.getLength() == 1) {
                        nodes = element
                                .getElementsByTagName(ObjProConstant.RULE);
                        for (int j = 0; j < nodes.getLength(); j++) {
                            node = nodes.item(j);
                            final String value = ContentDataParser
                                    .getTextNodeValue(node);
                            if (!TextUtils.isEmpty(value)) {
                                objPropCol.getDataRules().add(value);
                            }
                        }
                    }

                    if (objPropInfo.isLatitude()
                            || objPropInfo.getColumnName().equalsIgnoreCase(
                                    "Latitude")) {
                        objPropCol.setLatitudeCol(objPropInfo);
                    } else if (objPropInfo.isLongitude()
                            || objPropInfo.getColumnName().equalsIgnoreCase(
                                    "Longitude")) {
                        objPropCol.setLongitudeCol(objPropInfo);
                    }
                    objPropCol
                            .put(objPropInfo.getFullColumnName(), objPropInfo);

                    String queryColoum = null;
                    if (objPropInfo.getExpression() != null) {
                        queryColoum = objPropInfo.getExpression();
                    } else {
                        queryColoum = objPropInfo.getFullColumnName();
                    }
                    objPropCol.getQueriedColumns().add(
                            queryColoum + " AS "
                                    + objPropInfo.getAliasColumnName());
                    objPropCol.getSelectedColumn().add(objPropInfo);
                }
                try {
                    jsonObject.put(objPropInfo.getFullColumnName(),
                            webserviceVariable);
                } catch (final JSONException e) {
                    e.printStackTrace();
                }
            }
            if ((webserviceParameter != null) && !webserviceParameter.isEmpty()) {
                final GenericDictionary<String, JSONObject> hashMap = objPropCol
                        .getWebServiceParameters();
                // Merger webserviceParameter;
                if (hashMap.containsKey(webserviceParameter)) {
                    try {
                        final Iterator<String> it = jsonObject.keys();
                        while (it.hasNext()) {
                            final String key = it.next();
                            hashMap.get(webserviceParameter).put(key,
                                    jsonObject.get(key));
                        }
                    } catch (final JSONException e) {
                        e.printStackTrace();
                    }
                } else {
                    objPropCol.getWebServiceParameters().put(
                            webserviceParameter, jsonObject);
                }
            }
        }
        return objPropCol;
    }

    public ContentData parseIntoObjProp(final int xmlFileId) {
        try {
            final String tagname = ObjProConstant.OBJ_PROP_TAGNAME;
            final Document document = XMLPaserUtil.openDocumentFrom(xmlFileId);
            return ContentDataParser.parse(document, tagname);
        } catch (final ParserConfigurationException e) {
            e.printStackTrace();
        } catch (final SAXException e) {
            e.printStackTrace();
        } catch (final IOException e) {
            e.printStackTrace();
        } catch (final Resources.NotFoundException e) {
            e.printStackTrace();
        }
        return new ContentData();
    }

    public ContentData parseIntoObjProp(final int xmlFileId,
            final Context context) {
        try {
            final String tagname = ObjProConstant.OBJ_PROP_TAGNAME;
            final Document document = XMLPaserUtil.openDocumentFrom(xmlFileId,
                    context);
            return ContentDataParser.parse(document, tagname);
        } catch (final ParserConfigurationException e) {
            e.printStackTrace();
        } catch (final SAXException e) {
            e.printStackTrace();
        } catch (final IOException e) {
            e.printStackTrace();
        } catch (final Resources.NotFoundException e) {
            e.printStackTrace();
        }
        return new ContentData();
    }
}
